package com.geeguo.ebuilder.core.common.utils;

import com.geeguo.ebuilder.core.common.utils.key.UUIDGenerator;

import java.lang.management.ManagementFactory;
import java.net.*;
import java.util.Enumeration;

public class NodeIdGenerator {

    private static final String NODE_ID = generateNodeId();

    public static String getNodeId() {
        return NODE_ID;
    }

    private static String generateNodeId() {
        try {
            // 1. 获取本地IP地址（排除回环地址，确保取到真实网卡IP）
            String ip = getLocalIpAddress();
            // 2. 获取当前进程ID（Java 9+ 原生支持，低版本需兼容处理）
            long pid = getProcessId();
            // 3. 组合IP和PID作为节点标识
            return ip + ":" + pid;
        } catch (Exception e) {
            // 降级方案：使用UUID（缺点是节点重启后标识会变，尽量避免）
            return UUIDGenerator.get32Id();
        }
    }

    // 获取非回环的本地IP地址（避免127.0.0.1）
    private static String getLocalIpAddress() throws UnknownHostException, SocketException {
        InetAddress localHost = InetAddress.getLocalHost();
        // 排除回环地址（回环地址用于本机内部通信，如 127.0.0.1，其他机器无法访问）
        // 仅保留局域网内的IP（即私有 IP，如 192.168.x.x、10.x.x.x、172.16.x.x~172.31.x.x）
        if (!localHost.isLoopbackAddress() && localHost.isSiteLocalAddress()) {
            return localHost.getHostAddress();
        }
        // 遍历所有网卡，找第一个非回环IP
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface item = interfaces.nextElement();
            Enumeration<InetAddress> addresses = item.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (!address.isLoopbackAddress() && address instanceof Inet4Address) {
                    return address.getHostAddress();
                }
            }
        }
        // 兜底（可能是127.0.0.1，但集群中应避免这种情况）
        return localHost.getHostAddress();
    }

    // 获取当前进程ID（兼容Java 8及以上）
    private static long getProcessId() {
        // Java 9+ 推荐方式
        if (Runtime.version().feature() >= 9) {
            return ProcessHandle.current().pid();
        } else {
            // Java 8 兼容方案：从进程名中提取PID（依赖JVM实现，大部分环境有效）
            String processName = ManagementFactory.getRuntimeMXBean().getName();
            if (processName.contains("@")) {
                return Long.parseLong(processName.split("@")[0]);
            }
            // 极端情况降级（不推荐，但可运行）
            // 兜底（可能是127.0.0.1，但集群中应避免这种情况）
            return System.currentTimeMillis();
        }
    }
}